package com.shikx.demo.janino.compiler;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Kaixuan Shi
 * @since 2023/7/17
 */
public class JaninoCompilerDemo {
    public static void main(String[] args) {
        //region 构建源代码
        JavaSourceCode helloServiceSourceCode = new JavaSourceCode();
        helloServiceSourceCode.setSourceCode("package com.shikx.demo.janino.compiler;\n" +
                "\n" +
                "/**\n" +
                " * @author Kaixuan Shi\n" +
                " * @since 2023/7/17\n" +
                " */\n" +
                "public class HelloServiceSource {\n" +
                "\n" +
                "    public void sayHello() {\n" +
                "        System.out.println(\"Hello world!\");\n" +
                "    }\n" +
                "}\n");
        helloServiceSourceCode.setFullClassName("com.shikx.demo.janino.compiler.HelloServiceSource");

        JavaSourceCode outerClassSourceCode = new JavaSourceCode();
        outerClassSourceCode.setSourceCode("package com.shikx.demo.janino.compiler;\n" +
                "\n" +
                "/**\n" +
                " * @author Kaixuan Shi\n" +
                " * @since 2023/7/17\n" +
                " */\n" +
                "public class OuterClassSource {\n" +
                "\n" +
                "    public void sayHello(String name) {\n" +
                "        System.out.println(\"Hello, \" + name + \", I'm parent class instance\");\n" +
                "    }\n" +
                "\n" +
                "    public class InnerClass {\n" +
                "        public void sayHello(String name) {\n" +
                "            System.out.println(\"Hello, \" + name + \", I'm child class instance\");\n" +
                "        }\n" +
                "    }\n" +
                "}\n");
        outerClassSourceCode.setFullClassName("com.shikx.demo.janino.compiler.OuterClassSource");

        List<JavaSourceCode> sourceCodes = new ArrayList<>(2);
        sourceCodes.add(helloServiceSourceCode);
        sourceCodes.add(outerClassSourceCode);
        //endregion

        //调用编译服务
        CompileService compileService = new CompileService();
        compileService.compile(sourceCodes);

        //通过反射调用编译好的类
        try {
            //调用helloServiceSourceCode中的类
            Class<?> helloServiceClass = ClassLoaderService.loadClass(helloServiceSourceCode.getFullClassName());
            Method helloServiceSayHelloMethod = helloServiceClass.getDeclaredMethod("sayHello");
            helloServiceSayHelloMethod.invoke(helloServiceClass.newInstance());
            //调用outerClassSourceCode中的“OuterClassSource”外部类
            Class<?> outerClass = ClassLoaderService.loadClass(outerClassSourceCode.getFullClassName());
            Method outerClassSayHelloMethod = outerClass.getDeclaredMethod("sayHello", String.class);
            outerClassSayHelloMethod.invoke(outerClass.newInstance(), "Janino");
            //调用outerClassSourceCode中的“InnerClass”内部类
            Class<?> innerClass = ClassLoaderService.loadClass(
                    "com.shikx.demo.janino.compiler.OuterClassSource$InnerClass");
            Method innerClassChildClassSayHelloMethod = innerClass.getDeclaredMethod("sayHello", String.class);
            innerClassChildClassSayHelloMethod.invoke(
                    innerClass.getDeclaredConstructors()[0].newInstance(outerClass.newInstance()), "Janino");
        } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException |
                 InvocationTargetException e) {
            throw new RuntimeException(e);
        }
        System.out.println("完成Janino编译及调用演示");
    }
}